<template>
	<div>
		<hr />
		<p>我是optionData</p>
		<button @click="changeBtn">按钮改变data属性值</button>
		<button @click="resetData">重置data数据</button>
		<div>在data中定义的非响应式数据{{ $data._age.num }}</div>
		<div>{{ obj.name }}</div>
		<Son :name="propData.name" :fn="setName" />
		<div @click="num++">{{ doubleNum }}</div>
	</div>
</template>
<script>
import Son from "./Son.vue";
export default {
	name: "OuterOptionData",
	components: { Son },
	data() {
		/* data为什么定义成函数？
		当一个组件被定义，data 必须声明为返回一个初始数据对象的函数，
		因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象，
		则所有的实例将共享引用同一个数据对象！通过提供 data 函数，
		每次创建一个新实例后，我们能够调用 data 函数，
		从而返回初始数据的一个全新副本数据对象。
		*/
		return {
			_age: { num: 18 },
			// Object.freeze用于冻结数据
			obj: Object.freeze({ name: "响应式name" }),
			/*
			面试题：如何将一个数据定义成妃非响应式数据
					解决：
					1.不讲数据放在data中
					2.若必须放在data中
						属性名以“_”或“$”开头都不会被进行数据代理（但是页面使用就必须使用$data._属性名）
						使用 Object.freeze（）将数据进行冻结，使该对象所有的属性都变成只读属性，从而变成非响应式数据
			*/
			propData: {
				name: "我是要prop传递的name",
			},
			// 测试计算属性
			num: 1,
		};
	},
	components: { Son },
	mounted() {},
	// 不应该使用箭头函数来定义 method 函数，理由是箭头函数绑定了父级作用域的上下文，所以 this 将不会按照期望指向 Vue 实例
	methods: {
		changeBtn() {
			// this.obj.name = "改变的name";//通过这改变冻结数据会报错
			// 改变冻结的上一层
			this.obj = { name: "改变冻结的数据" };
			// 方法二：
			// this.obj = { ...this.obj };
		},

		// 定义重置定义的数据
		resetData() {
			Object.assign(this.$data, this.$options.data());
		},
		// 修改propData方法
		setName(name) {
			this.propData.name = name;
		},
	},
	// computed（计算属性）使用
	computed: {
		/* 使用场景:如果你想使用一个数据,可是你手头没有,
		但是你可以通过data或者props计算得到,那么就是用computed
		计算属性虽然是个方法,但是使用起来和普通的data数据相同
		计算属性会监视函数体中使用到的响应式属性,
		如果响应式属性发生变化就会重新计算,
		如果没有发生变化就会复用之前的计算结果(有缓存) */
		doubleNum() {
			return this.num * 2;
		},
	},
	// watch本是一个浅监听，
	// 注意，不应该使用箭头函数来定义 watcher 函数
	watch: {
		// 浅层监视写法：
		// propData() {
		// 	console.log("监视触发");
		// },

		// 深层监视首次触发：
		// propData: {
		// 	handler() {
		// 		console.log("监视触发");
		// 	},
		// 	deep: true, //深层监视
		// 	immediate: true, //首次触发
		// },
		// 对某个对象中的指定属性值：
		"propData.name": function () {
			console.log("监视触发");
		},
	},
};
</script>
<style scoped></style>
